package com.wch.SpringBootTestDemo.webmagic.extension;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.wch.SpringBootTestDemo.util.MetaClassUtil;

import net.sf.json.JSONArray;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

/**
 * add by WanChengHe 20190221 
 * 对webmagic的管道流进行改造，将爬取到的数据输出到数据库对应的表中
 * @author 19821
 * 考虑到适用性，最好不能够将表或者字段写死，最好是作为参数传进来
 * 初步设计方案：无参构造方法给一个默认的表（先在数据库中建好一个专门记录爬取的数据,有则插入，没有则创建），
 * 把爬取到的数据作为一个整体插入表中一个字段，插入时同时记录时间等相关内容，后面可以后台数据库对数据进行处理。
 * 有参构造方法，入参带一个已建好的表的表名，然后将爬取到的数据匹配字段填充到数据库表中。
 * 建议采用采用无参构造使用更好。
 */

@SuppressWarnings("all")
@Component
public class DBTablePipeline implements Pipeline {
	private Logger logger = LoggerFactory.getLogger(getClass());
	private String dateTable = "X_WEBMAGIC_DATA";
	private String seqName = "SEQUENCE_WEBMAGIC_ID";
	private String fieldStr = " ";
	private Map fieldMap;
	private String insertFields = "";
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public String getDateTable() {
		return dateTable;
	}

	private void setDateTable(String dateTable) {
		this.dateTable = dateTable.toUpperCase();
	}
		

	public String getSeqName() {
		return seqName;
	}

	private void setSeqName(String seqName) {
		this.seqName = seqName.toUpperCase();
	}

	/**
	 * 提供默认的存储表和序列，也可以通过此方法使用自己定义的表和序列
	 * @param dateTable  表名
	 * @param seqName  序列名
	 */
	public void newInstance(String dateTable,String seqName){
		this.setDateTable(dateTable);
		this.setSeqName(seqName);
	}

	/**
	 * 在每次将爬取数据插入后，表和序列恢复默认，
	 * 当使用者需要再次使用时可以直接使用，新爬取的数据存储到默认表中；
	 * 或者使用者可以再次指定表和序列。
	 * 主要是为了避免多次爬取的数据全部误存入用户指定的某一张表中。
	 * 后续可以考虑是否线程优化
	 */
	private void clearInstance(){
		dateTable = "X_WEBMAGIC_DATA";
		seqName = "SEQUENCE_WEBMAGIC_ID";
	}
	
	@Override
	public void process(ResultItems resultitems, Task task) {
		// TODO Auto-generated method stub
		//先确定表信息
		createTableInfo();
		System.out.println("----------------------------------");
		JSONArray recordMap = (JSONArray) resultitems.get("content");
		System.out.println("----------------------------------");
		for(int i=0;i<recordMap.size();i++){
			Map objectMap = (Map) recordMap.get(i);
		//	String test = object.get("title").toString();
			System.out.println("--------------");
		//	insertData(test);
			//insertData(objectMap);
			insertData(objectMap.toString());
			
			
		}
	/*	Entry entry;
		for (Iterator iterator = resultitems.getAll().entrySet().iterator(); 
				iterator.hasNext();
			System.out.println((new StringBuilder()).append((String) entry.getKey()).append(":\t").append(entry.getValue())
						.toString())
				insertData((new StringBuilder()).append((String) entry.getKey()).append(":\t").append(entry.getValue())
						.toString()))
			entry = (Entry) iterator.next();*/
		
		//爬取的数据插入完毕后恢复默认表
		clearInstance();		
	}
	
	/**
	 * 判断表是否存在，若存在则继续后面逻辑完成数据插入；
	 * 如果表不存在，则先创建默认表再继续后面的数据插入
	 * @param tableName 存储爬取数据的表名
	 */
	private void createTableInfo(){
		String tableSql = "SELECT COUNT(1) TABLECOUNT FROM USER_TABLES WHERE TABLE_NAME = ?";
		String seqSql = "SELECT COUNT(1) SEQCOUNT FROM USER_SEQUENCES A WHERE SEQUENCE_NAME = ?";
		
		logger.info(System.currentTimeMillis()+":"+seqSql);
		Map<String, Object> seqObject = jdbcTemplate.queryForMap(seqSql,new Object[]{seqName});
		//序列不存在，则默认创建序列
		if(null==seqObject || !("1".equals(seqObject.get("SEQCOUNT").toString()))){
			String createSeqSql = "CREATE SEQUENCE "+seqName+" MINVALUE 1 NOMAXVALUE INCREMENT BY 1 START WITH 1 NOCACHE";
			logger.info(System.currentTimeMillis()+":"+createSeqSql);
			jdbcTemplate.execute(createSeqSql);

		}
		logger.info(System.currentTimeMillis()+":"+tableSql);
		Map<String, Object> tableObject = jdbcTemplate.queryForMap(tableSql,new Object[]{dateTable});
		//表不存在，则默认创建表
		if(null==tableObject || !("1".equals(tableObject.get("TABLECOUNT").toString()))){   
			String createTableSql = "CREATE TABLE "+dateTable+" ( "
					+ "ID  INTEGER PRIMARY KEY NOT NULL,"
					+fieldStr
					+ "RECEIVEDATE DATE default SYSDATE"
					+ ")";
			logger.info(System.currentTimeMillis()+":"+createTableSql);
			jdbcTemplate.execute(createTableSql);
		}
	}
	
	/**
	 * 将爬取到的数据插入到我们指定的表中
	 * @param object 爬取到的数据
	 */
	private void insertData(Object object){
		String insertSql = "INSERT INTO "+dateTable+"(ID,INFO) VALUES("+seqName+".NEXTVAL,'"+object.toString()+"')";
		logger.info(System.currentTimeMillis()+":"+insertSql);
		jdbcTemplate.execute(insertSql);
	}
	
	/**
	 * 考虑插入的字段怎么一一匹配
	 * @param map
	 */
	private void insertData(Map map){
	//	String insertSql = "INSERT INTO "+dateTable+"(ID,"+insertFields+") VALUES("+seqName+".NEXTVAL,'"+map+"')";
		StringBuilder insertSql =new StringBuilder("INSERT INTO "+dateTable+"(ID ");
		for(int i=0;i<fieldMap.size();i++){
			insertSql.append("");
		}
		logger.info(System.currentTimeMillis()+":"+insertSql.toString());
		jdbcTemplate.execute(insertSql.toString());
	}
	
	/**
	 * 通过传入变参设置存储表的字段展示
	 * @param fields
	 */
	public void initTableField(String... fields){
		StringBuilder sb = new StringBuilder();
		for(int i=0;i<fields.length;i++){
			sb.append(fields[i].toUpperCase()+"  VARCHAR2(255),");
		}
		fieldStr = sb.toString();
	}
	
	/**
	 * 不带参数，则默认存储一条记录，存储在一个字段
	 */
	public void initTableField(){
		StringBuilder sb = new StringBuilder();
		sb.append("INFO  VARCHAR2(2550),");		
		fieldStr = sb.toString();
	}
	/**
	 * 通过传入map设置存储表的字段展示
	 * @param fields
	 */
	public void initTableField(Map fields){
		fieldMap = fields;
		StringBuilder sb = new StringBuilder();
		StringBuilder sb2 = new StringBuilder();
		for(int i=0;i<fields.size();i++){
			String key = fieldMap.get(i).toString().toUpperCase();
			sb2 = sb.append(" ,"+key);
			sb.append(key+"  VARCHAR2(255),");			
		}
		insertFields = sb2.toString();
		fieldStr = sb.toString();
	}

}
